<template>
  <div class="pagination-table">
    <div v-if="showQueryForm" class="pagination-table-query-form">
      <slot
        name="form"
        :submit="submit"
        :reset="reset"
        :bind-form="(ins: any) => (queryFormIns = ins)"
      ></slot>

      <div v-if="showTools" class="pagination-table-query-form-line"></div>
    </div>
    <vxe-toolbar
      v-if="showTools"
      ref="toolbarRef"
      class="pagination-table-main-tools"
    >
      <template #buttons>
        <slot
          name="actions"
          :instance="instance"
          :form-instance="queryFormIns"
        ></slot>
      </template>
      <template #tools>
        <el-tooltip v-if="importMethod" content="导入" trigger="hover">
          <el-button quaternary circle @click="importMethod">
            <template #icon>
              <el-icon>
                <icon-mdi-file-upload-outline/>
              </el-icon>
            </template>
          </el-button>
        </el-tooltip>

        <el-tooltip v-if="exportMethod" content="导出" trigger="hover">
          <el-button quaternary circle @click="exportMethod">
            <template #icon>
              <el-icon>
                <icon-mdi-download/>
              </el-icon>
            </template>
          </el-button>
        </el-tooltip>

        <el-tooltip trigger="hover" content="刷新">
          <el-button quaternary circle @click="() => refresh()">
            <template #icon>
              <el-icon>
                <icon-mdi-table-refresh/>
              </el-icon>
            </template>
          </el-button>
        </el-tooltip>

        <el-tooltip trigger="hover" content="密度">
          <el-button quaternary circle @click="changeSize">
            <template #icon>
               <el-icon>
                <icon-mdi-arrow-expand-vertical/>
               </el-icon>
            </template>
          </el-button>
        </el-tooltip>

        <el-popover
          placement="bottom"
          content-style="max-height: 300px"
          scrollable
          trigger="click"
        >
          <div
            v-for="(item, index) in tableColumns"
            :key="index"
            style="margin-bottom: 4px"
            class="pagination-table-table-column-item"
          >
            <el-checkbox
              :checked="item.visible"
              :label="item.title || item.field"
              @change="(value) => handleCheckChange(value as boolean, index)"
            >
            </el-checkbox>
          </div>
          <template #reference>
            <div style="margin: 0 12px">
              <el-tooltip trigger="hover" content="列设置">
                <el-button quaternary circle>
                  <template #icon>
                    <el-icon>
                      <icon-mdi-cog-outline/>
                    </el-icon>
                  </template>
                </el-button>
              </el-tooltip>
            </div>
          </template>
        </el-popover>
      </template>
    </vxe-toolbar>
    <div class="pagination-table-main">
      <div
        v-if="paged && tablePagination.pageSize > 20"
        class="pagination-table-footer"
      >
        <el-pagination
          layout="prev, pager, next, sizes"
          :current-page="tablePagination.currentPage"
          :page-size="tablePagination.pageSize"
          :total="tablePagination.totalCount"
          :page-sizes="pageSizes"
          hide-on-single-page
          background
          @size-change="tablePagination.onPageSizeChange"
          @current-change="tablePagination.onCurrentPageChange"
        />
      </div>
      <vxe-table
        :ref="(tableIns: VxeTableInstance) => (vxetableInstance = tableIns)"
        v-bind="tableProps"
        :size="tableSize"
        :data="tablePagination.dataList"
        :loading="tablePagination.loading"
        :empty-render="{ name: 'ElEmpty' }"
        @sort-change="handleSortChange"
      >
        <slot></slot>
      </vxe-table>
      <div v-if="paged" class="pagination-table-footer">
        <el-pagination
          layout="prev, pager, sizes, next"
          :current-page="tablePagination.currentPage"
          :page-size="tablePagination.pageSize"
          :total="tablePagination.totalCount"
          :page-sizes="pageSizes"
          background
          @size-change="tablePagination.onPageSizeChange"
          @current-change="tablePagination.onCurrentPageChange"
        />
      </div>
    </div>
  </div>
</template>

<script lang="ts">
  import { ref, computed, provide } from 'vue';
  import {
    type VxeTablePropTypes,
    type VxeTableInstance,
    type VxeTableProps,
    type VxeTableEvents,
    type VxeToolbarInstance
  } from 'vxe-table';
  import { type FormInstance } from 'element-plus';
  import useTable from './usePage';
  import PaginationTableProps, { customProps } from './props';
  import { useCycleList, useVModel } from '@vueuse/core';
  import { PAGEINATION_INSTANCE } from './index';

  export default {
    name: 'PaginationTable',
    props: PaginationTableProps,

    setup(props, ctx) {
      /** 筛选表单表单实例 */
      const queryFormIns = ref<FormInstance>();
      /**  筛选表单数据 */
      const formData = useVModel(props, 'formData', ctx.emit);

      const defaultSort = computed(() => {
        if (Array.isArray(props.sortConfig.defaultSort)) {
          return props.sortConfig.defaultSort[0];
        }
        return props.sortConfig.defaultSort;
      });

      const verifyParameter = async () => {
        await queryFormIns.value?.validate();
        return Promise.resolve(formData.value);
      };

      const submit = () =>
        queryFormIns.value?.validate().then(() => refresh(true));

      const reset = () => {
        // 筛选表单重置
        queryFormIns.value?.resetFields();
        // table事件重置
        vxetableInstance.value?.clearAll();
        // 清楚table缓存
        tablePagination.value.reset();
        // 等待页面参数更改后刷新
        setTimeout(() => refresh(true));
      };

      const tablePagination = useTable({
        paged: props.paged,
        load: props.load!,
        verifyParameter,
        beforeInit: props.beforeInitTable,
        afterLoaded: props.afterLoadedTable,
        sortField: defaultSort.value?.field,
        sortOrder: defaultSort.value?.order
      });

      const vxetableInstance = ref<VxeTableInstance>();

      const toolbarRef = ref<VxeToolbarInstance>();

      const tableColumns = ref<any[]>([]);

      const EventMap = ref<Map<string, (args?: any) => any>>(new Map());

      const { state: tableSize, next: nextSize } =
        useCycleList<VxeTablePropTypes.Size>(['mini', 'small', 'medium'], {
          initialValue: 'medium'
        });

      const on = (eventname: string, handle: (args?: any) => any) => {
        EventMap.value.set(eventname, handle);
      };

      const getTableInstance = () => vxetableInstance.value;

      const getTableData = () => tablePagination.value.dataList;

      const setTableData = (list: unknown[]) =>
        (tablePagination.value.dataList = list);

      const setLoading = (loading: boolean) =>
        tablePagination.value.setLoading(loading);
      /** table的一些方法 */
      const refresh = async (
        research = false /** 是否需要重置页码进行刷新 */
      ) => {
        await tablePagination.value.refresh.apply(null, [research]);
        const eventHandle = EventMap.value.get('refresh');
        if (eventHandle) eventHandle.call(null, props);
        return Promise.resolve();
      };

      const handleSortChange: VxeTableEvents.SortChange = async ({
        field,
        order
      }) => {
        await tablePagination.value.onSortChange(field, order);
        const eventHandle = EventMap.value.get('sortChange');
        if (eventHandle) eventHandle.call(null, props);
        return Promise.resolve();
      };

      const changeSize = () => {
        nextSize();
        const eventHandle = EventMap.value.get('changeSize');
        if (eventHandle) eventHandle.call(null, props);
      };

      const handleCheckChange = (value: boolean, index: number) => {
        tableColumns.value[index].visible = value;
        vxetableInstance.value?.refreshColumn();
        const eventHandle = EventMap.value.get('checkChange');
        if (eventHandle) eventHandle.call(null, props);
      };

      const ins = {
        submit,
        on,
        reset,
        refresh,
        getTableInstance,
        getTableData,
        setTableData,
        setLoading
      };

      ctx.expose(ins);

      provide(PAGEINATION_INSTANCE, ins);

      return {
        queryFormIns,
        vxetableInstance,
        toolbarRef,
        refresh,
        submit,
        reset,
        tablePagination,
        handleSortChange,
        changeSize,
        tableSize,
        tableColumns,
        handleCheckChange,
        instance: ins
      };
    },

    computed: {
      showQueryForm(): boolean {
        return !!this.$slots['form'];
      },
      tableProps(): VxeTableProps {
        const keys = Object.keys(customProps);
        const tprops: VxeTableProps = {};
        Object.entries(this.$props).forEach(([key, value]) => {
          if (!keys.includes(key)) tprops[key as keyof VxeTableProps] = value;
        });
        /** 透传props 和 事件 */
        const attrsWithoutClass = { ...this.$attrs };
        delete attrsWithoutClass['class'];
        return { ...tprops, ...attrsWithoutClass };
      }
    },

    mounted() {
      this.$nextTick(() => {
        const $table = this.vxetableInstance;
        if ($table) {
          const $toolbar = this.toolbarRef;
          if ($toolbar) $table.connect($toolbar);
          this.tableColumns = $table.getColumns().filter((item) => {
            return !!item.field;
          });
          this.tableColumns.forEach((item) => {
            item.visible = true;
          });
        }

        if (this.$props.autoLoad) this.refresh(true);
      });
    }
  };
</script>

<style lang="less" scoped>
  .pagination-table {
    display: flex;
    flex-direction: column;
  }
  .pagination-table-header {
    font-size: 16px;
    margin-bottom: 15px;
  }
  .pagination-table-query-form {
    padding-top: 15px;
    border-radius: 4px 4px 0 0;
    &-line {
      border-bottom: 1px solid var(--el-border-color);
    }
  }
  .pagination-table-main-tools {
    padding: 15px 0;
  }
  .pagination-table-main {
    flex: 1;
    overflow: hidden;
    display: flex;
    flex-direction: column;
  }
  .pagination-table-footer {
    flex-shrink: 0;
    display: flex;
    justify-content: flex-end;
    padding: 10px 15px;
  }
  .pagination-table-table-column-item {
    .el-checkbox {
      white-space: normal;
    }
  }
</style>
